package com.gitee.auth;


import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.common.DefaultThrowableAnalyzer;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.util.ThrowableAnalyzer;

import javax.annotation.Resource;

/**
 * @author EalenXie create on 2020/11/3 11:34
 */

@Configuration
@Import(AuthConfig.class)
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {


    @Resource
    private DefaultTokenServices tokenServices;
    @Resource
    private AuthenticationManager authenticationManagerBean;
    @Resource
    public AuthenticationEntryPoint authenticationEntryPoint;
    @Resource
    private JdbcClientDetailsService jdbcClientDetailsService;


    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        // 开启/oauth/token_key验证端口无权限访问
        security.tokenKeyAccess("permitAll()")
                // 关闭/oauth/check_token验证端口认证权限访问
                .checkTokenAccess("permitAll()")
                .authenticationEntryPoint(authenticationEntryPoint);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(jdbcClientDetailsService);
    }


    @Override
    @SuppressWarnings({"unchecked", "rawtypes"})
    public void configure(AuthorizationServerEndpointsConfigurer configurer) {
        configurer
                .tokenServices(tokenServices)
                .authenticationManager(authenticationManagerBean)
                .exceptionTranslator(new WebResponseExceptionTranslator() {
                    private final ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();

                    private ResponseEntity handleOAuth2Exception(OAuth2Exception e) {
                        HttpStatus httpStatus = HttpStatus.resolve(e.getHttpErrorCode());
                        if (httpStatus == null) httpStatus = HttpStatus.UNAUTHORIZED;
                        HttpHeaders headers = new HttpHeaders();
                        headers.set("Cache-Control", "no-store");
                        headers.set("Pragma", "no-cache");
                        if ((e instanceof InsufficientScopeException)) {
                            headers.set("WWW-Authenticate", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getSummary()));
                        }
                        return new ResponseEntity<>("{\"code\":\"" + httpStatus + "\",\"message\":\"Forbidden\",\"data\":\"" + e.getMessage() + "\"}", headers, httpStatus);
                    }

                    @Override
                    public ResponseEntity translate(Exception e) {
                        Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e);
                        OAuth2Exception ase = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(OAuth2Exception.class, causeChain);
                        if (ase != null) {
                            return handleOAuth2Exception(ase);
                        }
                        return new ResponseEntity<>("{\"code\":\"" + HttpStatus.UNAUTHORIZED + "\",\"message\":\"Forbidden\",\"data\":\"" + e.getMessage() + "\"}", HttpStatus.UNAUTHORIZED);
                    }

                });
    }


}
